package options

import (
	"context"
	"strings"
	"sync"
	"zxs-micro-2/zxs-micro-common/codec/http_codec"
	"zxs-micro-2/zxs-micro-common/zxsContext"
)

type Option func(ctx context.Context) (context.Context, error)

var oLock sync.Mutex

//todo 此处应该有一个链路。。
//链路首先要解析服务的请求协议类型，然后解析请求参数和route，然后才是限流和灰度之类的功能
var CtxOptions = []Option{ProtocolHandleOption}
var RouteOptions = []Option{}

func AddNewCtxOption(o Option) {
	oLock.Lock()
	CtxOptions = append(CtxOptions, o)
	oLock.Unlock()
}

func AddNewRouteOption(o Option) {
	oLock.Lock()
	RouteOptions = append(RouteOptions, o)
	oLock.Unlock()
}

func ProtocolHandleOption(ctx context.Context) (context.Context, error) {
	msg, ok := ctx.Value(zxsContext.CTX_MSG_KEY).(*zxsContext.ZxsContextMsg)
	if !ok {
		//不是zxs-micro的ctx。。。为什么？
		return ctx, zxsContext.UnknownContextError
	}
	head, ok := msg.GetValue(zxsContext.CTX_HTTP_HEAD_KEY).(*zxsContext.ZxsHttpHead)
	trMap := make(map[string]interface{})
	//正常说明是http请求，不正常说明是grpc请求。先吧http请求的弄出来吧
	if ok {
		serializationType, ok := msg.GetValue("SerializationType").(int)
		m := make(map[string]interface{})
		var err error
		if !ok {
			//没获取到，说明没有这个字段，就当作get请求处理
			serializationType = 0
			err = http_codec.HttpSerializerUnMarshal(0, head.ReqBody, &m)
		} else {
			err = http_codec.HttpSerializerUnMarshal(serializationType, head.ReqBody, &m)
		}
		if err != nil {
			return ctx, err
		}
		trMap["remote_ip"] = strings.Split(head.Request.RemoteAddr, ":")[0]
		trMap["method"] = head.Request.Method
		trMap["SerializationType"] = serializationType
		for k, v := range head.Request.Header {
			trMap[k] = stringSlice2InterfaceSlice(v)
		}
		for k, v := range m {
			trMap[k] = v
		}
		msg.AddValue(zxsContext.CTX_CONTEXT_REQ_HEAD_KEY, head.ReqBody)
		msg.AddValue(zxsContext.CTX_CONTEXT_OPTION_KEY, trMap)
		msg.AddValue(zxsContext.CTX_REQUEST_VALUE_KEY, m)
	}
	context.WithValue(ctx, zxsContext.CTX_MSG_KEY, msg)
	return ctx, nil
}

func stringSlice2InterfaceSlice(ss []string) []interface{} {
	is := make([]interface{}, len(ss))
	for i, o := range ss {
		is[i] = o
	}
	return is
}
